package edu.uwaterloo.bicycle.framework;

import edu.uwaterloo.bicyclecomputer.modefunctions.SystemValues;
import edu.uwaterloo.bicycle.framework.ShapedFrameUtils.Result;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;

public class ShapedFrame extends JFrame {
  private static final long serialVersionUID = 1L;

  public static boolean isPerpixelTranslucencySupported(final GraphicsConfiguration configuration) {
    return configuration.getDevice().isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT);
  }

  public static boolean isPerpixelTransparencySupported(final GraphicsConfiguration configuration) {
    return configuration.getDevice().isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT);
  }

  public static boolean isTranslucencyCapable(final GraphicsConfiguration configuration) {
    return configuration.isTranslucencyCapable();
  }

  public static boolean isTranslucencySupported(final GraphicsConfiguration configuration) {
    return configuration.getDevice().isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.TRANSLUCENT);
  }

 

  protected static boolean start(final GraphicsConfiguration configuration) throws Exception {
    if (!ShapedFrame.isTranslucencySupported(configuration)) {
      return false;
    }
    if (!ShapedFrame.isPerpixelTranslucencySupported(configuration)) {
      return false;
    }
    if (!ShapedFrame.isPerpixelTransparencySupported(configuration)) {
      return false;
    }
    if (!ShapedFrame.isTranslucencyCapable(configuration)) {
      return false;
    }
    new ShapedFrame(configuration).setVisible(true);
    return true;
  }

  public void setWindowOpaque(final boolean b) {
	    this.setBackground(new Color(b ? this.getBackground().getRGB() & 0x00FFFFFF : this.getBackground().getRGB() | 0xFF000000));
	  }
  
  public ShapedFrame() throws Exception {
	    super();
	    init();
	  }

  public ShapedFrame(final GraphicsConfiguration configuration) throws Exception {
    super(configuration);
    init();
  }
  
  
  protected Result result;
  protected JPanel pnlBack;
 

  protected void init() throws Exception 
  {
	  	this.setUndecorated(true);
	  	this.setLocationRelativeTo(null);
	  	this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	  	final MoveMouseListener mml = new MoveMouseListener(this);
		this.addMouseListener(mml);
		this.addMouseMotionListener(mml);
		
		this.result = ShapedFrameUtils.restore("comp4");
		this.setMinimumSize(this.result.size);
		this.setMaximumSize(this.result.size);
		this.setResizable(false);
		this.setSize(this.result.size);
		this.setLayout(new BorderLayout());
		
		this.addKeyListener(new KeyListener() {
			
			@Override
			public void keyTyped(KeyEvent e) {
				
				
			}
			
			@Override
			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub
				if(e.getKeyCode() == 114){
					System.out.print("pressed");
				}
			}
			
			@Override
			public void keyPressed(KeyEvent e) {
				// TODO Auto-generated method stub
				
			}
		});
	
		this.pnlBack = new JPanel() 
	    {
	    	private static final long serialVersionUID = 1L;
	
	    	@Override
	    	public void paintComponent(final Graphics g) 
	    	{
		        if ((ShapedFrame.this.result != null) && (ShapedFrame.this.result.image != null)) 
		        {
		        	g.drawImage(ShapedFrame.this.result.image, 0, 0, null);
		        } else {
		        	super.paint(g);
		        }
	    	}	    	
	    };
	    
	    this.pnlBack.addKeyListener(new KeyListener() {
			
			@Override
			public void keyTyped(KeyEvent arg0) {
				// TODO Auto-generated method stub
				//System.out.print("pressed" + arg0.getKeyCode());
			}
			
			@Override
			public void keyReleased(KeyEvent arg0) {
				// TODO Auto-generated method stub
				System.out.print("pressed" + arg0.getKeyCode());
				if(arg0.getKeyCode() == 82){
					
				}
			}
			
			@Override
			public void keyPressed(KeyEvent arg0) {
				// TODO Auto-generated method stub
				//if(e.getKeyCode() == 114){
					//System.out.print("pressed" + arg0.getKeyCode());
				//}
			}
		});
	    pnlBack.setFocusable(true);
	    this.pnlBack.setLayout(null);
	    this.add(this.pnlBack, BorderLayout.CENTER);
	    
 final ShapedButton btnClose = new ShapedButton("exit");
	    
	    btnClose.addActionListener(new ActionListener() 
	    	{
	    		@Override
	    		public void actionPerformed(final ActionEvent e) 
	    		{
	    			/*timerParking.cancel();
	    			timerRiding.cancel();
	    			ShapedFrame.this.dispose();*/
	    			isActive = false;
					
						try {
							for(int i=0; i<modes.length;i++)
							{
								modes[i].getField("value").set(null, 0);
								modes[i].getField("error").set(null,false);
								modes[i].getField("overflow").set(null,false);
							}
							
							lblMain.setText((String)modeSpeed.getMethod("getString").invoke(null));
			  			  	lblActiveModeValue.setText((String)modes[currentModeIndex].getMethod("getString").invoke(null));
						} catch (IllegalArgumentException exp) {
							// TODO Auto-generated catch block
							exp.printStackTrace();
						} catch (IllegalAccessException exp) {
							// TODO Auto-generated catch block
							exp.printStackTrace();
						} catch (NoSuchFieldException exp) {
							// TODO Auto-generated catch block
							exp.printStackTrace();
						} catch (SecurityException exp) {
							// TODO Auto-generated catch block
							exp.printStackTrace();
						} catch (InvocationTargetException exp) {
							// TODO Auto-generated catch block
							exp.printStackTrace();
						} catch (NoSuchMethodException exp) {
							// TODO Auto-generated catch block
							exp.printStackTrace();
						}
					
	    		}
	    	}
	    );
	    
	    
	    btnClose.setBounds(235,517,32,32);
	    this.pnlBack.add(btnClose);
	    
	    lblMain = new JLabel("0.0");
	    lblMain.setBounds(155,105,212,111);
	    lblMain.setHorizontalAlignment(SwingConstants.RIGHT);
	    lblMain.setFont(new Font("Tahoma", Font.PLAIN, 80));
	    lblMain.setForeground(Color.BLACK);
	    this.pnlBack.add(lblMain);
	    
	    lblKmHr = new JLabel();
	    lblKmHr.setBounds(370,105,100,111);
	    lblKmHr.setHorizontalAlignment(SwingConstants.LEFT);
	    lblKmHr.setFont(new Font("Tahoma", Font.PLAIN, 30));
	    lblKmHr.setForeground(Color.BLACK);
	    lblKmHr.setText("<html>KM<br>HR</html>");
	    this.pnlBack.add(lblKmHr);
	    
	    lblParking = new JLabel();
	    lblParking.setBounds(90,105,30,111);
	    lblParking.setHorizontalAlignment(SwingConstants.LEFT);
	    lblParking.setFont(new Font("Tahoma", Font.PLAIN, 50));
	    lblParking.setForeground(Color.BLACK);
	    lblParking.setText("P");
	    this.pnlBack.add(lblParking);
	    
	    lblActiveModeName = new JLabel();
	    lblActiveModeName.setBounds(90,237,120,80);
	    lblActiveModeName.setHorizontalAlignment(SwingConstants.LEFT);
	    lblActiveModeName.setFont(new Font("Tahoma", Font.PLAIN, 35));
	    lblActiveModeName.setForeground(Color.BLACK);
	    lblActiveModeName.setText("XXXX");
	    this.pnlBack.add(lblActiveModeName);
	    
	    
	    lblActiveModeValue = new JLabel();
	    lblActiveModeValue.setBounds(85,235,320,80);  
	    lblActiveModeValue.setHorizontalAlignment(SwingConstants.RIGHT);
	    lblActiveModeValue.setFont(new Font("Tahoma", Font.PLAIN, 45));
	    lblActiveModeValue.setForeground(Color.BLACK);
	    this.pnlBack.add(lblActiveModeValue);
	    
	    final ShapedButton btnMode = new ShapedButton("bLeft");
	    btnMode.setBounds(100,391,125,125);
	    
	    btnMode.addActionListener(new ActionListener() 
			{
				@Override
				public void actionPerformed(final ActionEvent e) 
				{					
					if(modes.length == 0) return;
					currentModeIndex = FindNextVisibleMode(currentModeIndex);
					try 
					{
						lblActiveModeName.setText((String)modes[currentModeIndex].getField("name").get(null));
						lblActiveModeValue.setText((String)modes[currentModeIndex].getMethod("getString").invoke(null));
					} catch (IllegalArgumentException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					} catch (IllegalAccessException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					} catch (NoSuchFieldException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					} catch (SecurityException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					} catch (InvocationTargetException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					} catch (NoSuchMethodException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}					
				}
				
			}
		);
	    
	    pnlBack.add(btnMode);
	            
	    final ShapedButton btnStartStop = new ShapedButton("bRight");
	    btnStartStop.setBounds(280,390,125,125);
	    
	    btnStartStop.addActionListener(new ActionListener() 
			{
				@Override
				public void actionPerformed(final ActionEvent e) 
				{					
					if(!isActive)
					{					
						lblParking.setVisible(false);
					}					
					isActive = !isActive;
				}
			}
		);
	    
	    pnlBack.add(btnStartStop);
	    
	    this.setWindowOpaque(false);
	    this.setOpacity(1);
	    this.setShape(this.result.shape);
	    
	    InitLogic();
	 
  }
  
  
  
  public static Class[] getClasses() throws IOException, ClassNotFoundException {
		BufferedReader in = new BufferedReader(new FileReader("_ModesList.txt"));
		ArrayList<Class> arrList = new ArrayList<Class>();
		while (in.ready())
			arrList.add(Class.forName("edu.uwaterloo.bicyclecomputer.modefunctions." + in.readLine()));
		in.close();
		return arrList.toArray(new Class[arrList.size()]);
	}
  
  public static void main(final String[] args) throws Exception {
	    final GraphicsConfiguration defaultConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
	    if ((ShapedFrame.isTranslucencyCapable(defaultConfiguration))) {
	      if ((ShapedFrame.isPerpixelTranslucencySupported(defaultConfiguration))) {
	        if (ShapedFrame.start(defaultConfiguration)) {
	          return;
	        }
	      }
	    }
	    for (final GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
	      if ((ShapedFrame.isPerpixelTranslucencySupported(defaultConfiguration))) {
	        for (final GraphicsConfiguration configuration : device.getConfigurations()) {
	          if (ShapedFrame.start(configuration)) {
	            return;
	          }
	        }
	      }
	    }
	  }





JLabel lblMain;
JLabel lblActiveModeValue;
JLabel lblKmHr;
JLabel lblParking;
JLabel lblActiveModeName;
Class[] modes;
boolean[] visibility;
Class modeSpeed;
int currentModeIndex;
java.util.Timer timerRiding;
java.util.Timer timerParking;
boolean isActive = false;




protected void InitLogic() throws Exception
{
	  	modes = getClasses();
		if(modes.length == 0) throw new Exception();		
		visibility = new boolean[modes.length];
		for(int i = 0; i < modes.length; i++)
		{
			if(((String) modes[i].getField("name").get(null)) == "spd") modeSpeed = modes[i];
			visibility[i] = !(Boolean) modes[i].getField("invisible").get(null);
		}
		currentModeIndex = FindNextVisibleMode(-1);
		SystemValues.rot = 0;
		
		timerParking = new Timer();
		timerParking.schedule(new ParkingFlashingTimerTask(), 10, 500);
		
		
		timerRiding = new Timer();
		timerRiding.schedule(new TimeTrigerTimerTask(), 10, 1000);
		
		lblActiveModeName.setText((String)modes[currentModeIndex].getField("name").get(null));
		lblActiveModeValue.setText((String)modes[currentModeIndex].getMethod("getString").invoke(null));
} 

private int FindNextVisibleMode(int startIndex) 
{
	  	for(int i = startIndex + 1; i < visibility.length; i++)
	  	{
	  		if(visibility[i])
	  		{
	  			return i;
	  		}
	  	}
	  	for(int i = 0; i <= startIndex; i++)
	  	{
	  		if(visibility[i])
	  		{
	  			return i;
	  		}
	  	}
		return -1;
}


class ParkingFlashingTimerTask extends TimerTask {
    public void run()
    {
  	  if(!isActive)
  	  {
  		  lblParking.setVisible(!lblParking.isVisible());
  	  }
    }
}

class TimeTrigerTimerTask extends TimerTask 
{
	  protected Random r = new Random();
	  
	 
	  public void run()
    {		  
  	  if(isActive)
  	  {
  		  SystemValues.rot = 1 + r.nextInt(8);
  		  
  		  for (int j = 0; j < modes.length; j++) 
  		  {
  			  Method m;
  			  try {
  				  m = modes[j].getMethod("calculate");
  				  m.invoke(null);
  			  } catch (NoSuchMethodException e) {
					// TODO Auto-generated catch block
  				  e.printStackTrace();
  			  } catch (SecurityException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
  			  } catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
  			  } catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
  			  } catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
  			  }  				
  		  }
  		  System.out.print(SystemValues.rot + " -> " + SystemValues.rot * SystemValues.cir / 100 * 3.6 + "\n");
  		  try
  		  {    			  
  			  lblMain.setText((String)modeSpeed.getMethod("getString").invoke(null));
  			  lblActiveModeValue.setText((String)modes[currentModeIndex].getMethod("getString").invoke(null));
  		  } 
  		  catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
  		  } 
  		  catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
  		  } 
  		  catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
  		  } 
  		  catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
  		  } 
  		  catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
  		  }
  	  }
  	  
  	  
    }
}
}

